package com.feedgraph;

import java.io.File;
import java.io.IOException;

import com.feedgraph.FeedManager.FeedItem;
import com.feedgraph.PlacesService.PlaceListener;

import android.net.http.HttpResponseCache;
import android.os.Bundle;
import android.os.IBinder;
import android.app.ListActivity;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.CursorAdapter;
import android.widget.Toast;

/**
 * Example Activity which uses {@link AsycFeedLoader} to display
 * {@link FeedItem}s
 * 
 * @author ryanne
 */
abstract public class FeedViewActivity extends ListActivity implements
		LoaderCallbacks <Cursor>, PlaceListener {

	static final int LOADER_ID = 0;
	protected Cursor mCursor;
	protected FeedManager mFeedManager;

	protected FeedService mFeedService;
	private boolean mSwipeToDelete;
	
	public FeedViewActivity(boolean swipeToDelete) {
		super();
		
		mSwipeToDelete = swipeToDelete;
	}

	private ServiceConnection mFeedServiceConn = new ServiceConnection () {

		@Override
		public void onServiceConnected (ComponentName arg0, IBinder service) {

			mFeedService = ((FeedService.LocalBinder) service).getService ();

			onAddSources (mFeedService);

			Log.d (getClass ().getSimpleName (), "bound to FeedService");
		}

		@Override
		public void onServiceDisconnected (ComponentName name) {

			mFeedService = null;

			Log.d (getClass ().getSimpleName (), "disconnected from FeedService");

		}

	};

	private boolean mIsFeedBound;

	private boolean mIsPlaceBound;

	private PlacesService mPlaceService;

	private ServiceConnection mPlaceServiceConn = new ServiceConnection () {
		public void onServiceConnected (ComponentName className, IBinder service) {
			// This is called when the connection with the service has been
			// established, giving us the service object we can use to
			// interact with the service. Because we have bound to a explicit
			// service that we know is running in our own process, we can
			// cast its IBinder to a concrete class and directly access it.
			mPlaceService = ((PlacesService.LocalBinder) service).getService ();
			mPlaceService.requestLocationUpdates (15 * 60 * 1000, 1);
			mPlaceService.addListener (FeedViewActivity.this, 100, new String [] {
					"bar", "cafe", "night_club", "restaurant" });

			Log.d (getClass ().getSimpleName (), "bound to PlaceService");
		}

		public void onServiceDisconnected (ComponentName className) {
			// This is called when the connection with the service has been
			// unexpectedly disconnected -- that is, its process crashed.
			// Because it is running in our same process, we should never
			// see this happen.
			mPlaceService = null;

			Log.d (getClass ().getSimpleName (), "disconnected from PlaceService");
		}
	};

	protected void bindFeedService () {
		Log.d (getClass ().getSimpleName (), "binding to FeedService");

		// Establish a connection with the service. We use an explicit
		// class name because we want a specific service implementation that
		// we know will be running in our own process (and thus won't be
		// supporting component replacement by other applications).

		boolean success = bindService (FeedService.getIntent (this), mFeedServiceConn,
				Context.BIND_AUTO_CREATE);
		
		if (!success) {
			throw new Error("failed to bind to FeedService");
		}
		
		mIsFeedBound = true;
	}
	protected void bindPlaceService () {
		// Establish a connection with the service. We use an explicit
		// class name because we want a specific service implementation that
		// we know will be running in our own process (and thus won't be
		// supporting component replacement by other applications).

		boolean success = bindService (PlacesService.getIntent (this), mPlaceServiceConn,
				Context.BIND_AUTO_CREATE);
		
		if (!success) {
			throw new Error("failed to bind to PlaceService");
		}
		
		mIsPlaceBound = true;
	}
	protected Cursor getCursor () {
		return mCursor;
	}
	/**
	 * override this to set your own sources
	 * 
	 * @param feed
	 */
	abstract protected void onAddSources (FeedService feed);

	@Override
	protected void onCreate (Bundle savedInstanceState) {
		super.onCreate (savedInstanceState);
		requestWindowFeature (Window.FEATURE_INDETERMINATE_PROGRESS);
    setProgressBarVisibility(true);

		mFeedManager = new FeedManager (this);

		try {
			File httpCacheDir = new File (getCacheDir (), "http");
			long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
			HttpResponseCache.install (httpCacheDir, httpCacheSize);
		}
		catch (IOException e) {
			Log.i ("HttpResponseCache", "HTTP response cache installation failed:"
					+ e);
		}

		bindFeedService ();

		LoaderManager lm = getLoaderManager ();
		lm.initLoader (LOADER_ID, null, this);
		
		if (mSwipeToDelete) {
			GestureDetector gestureDetector = new GestureDetector(this, new GestureListener());
			getListView().setOnTouchListener (new TouchListener(gestureDetector));
		}
	}

	@Override
	final public Loader <Cursor> onCreateLoader (int id, Bundle args) {
		return mFeedManager.makeLoader ();
	}

	@Override
	protected void onDestroy () {
		unbindFeedService ();
		super.onDestroy ();
	}

	@Override
	final public void onLoaderReset (Loader <Cursor> arg0) {
		((CursorAdapter) getListAdapter ()).swapCursor (null);
	}

	@Override
	final public void onLoadFinished (Loader <Cursor> arg0, Cursor c) {
    setProgressBarVisibility(false);
		Log.d ("FeedViewActivity", "finished loading");
		((CursorAdapter) getListAdapter ()).swapCursor (c);
	}

	@Override
	public void onStop () {
		HttpResponseCache cache = HttpResponseCache.getInstalled ();
		if (cache != null) {
			cache.flush ();
		}

		super.onStop ();
	}

	protected void unbindFeedService () {
		if (mIsFeedBound) {
			// Detach our existing connection.
			unbindService (mFeedServiceConn);
			mIsFeedBound = false;
		}
	}

	protected void unbindPlaceService () {
		if (mIsPlaceBound) {
			// Detach our existing connection.
			unbindService (mPlaceServiceConn);
			mIsPlaceBound = false;
		}
	}

	protected PlacesService getPlaceService() {
		return mPlaceService;
	}
	
	protected FeedService getFeedService() {
		return mFeedService;
	}
	
	protected class GestureListener extends SimpleOnGestureListener
	{
	    private static final int SWIPE_MIN_DISTANCE = 150;
	    private static final int SWIPE_MAX_OFF_PATH = 100;
	    private static final int SWIPE_THRESHOLD_VELOCITY = 100;

	    private MotionEvent mLastOnDownEvent = null;

	    @Override
	    public boolean onDown(MotionEvent e)
	    {
	        mLastOnDownEvent = e;
	        return super.onDown(e);
	    }

	    @Override
	    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
	    {
	    	
	    	Log.d("Gesture", "onFling");
	        if(e1 == null){
	            e1 = mLastOnDownEvent;
	        }
	        if(e1==null || e2==null){
	            return false;
	        }

	        float dX = e2.getX() - e1.getX();
	        float dY = e1.getY() - e2.getY();

	        if (Math.abs(dY) < SWIPE_MAX_OFF_PATH && Math.abs(velocityX) >= SWIPE_THRESHOLD_VELOCITY && Math.abs(dX) >= SWIPE_MIN_DISTANCE ) {
	            if (dX > 0) {
	                Toast.makeText(getApplicationContext(), "Right Swipe", Toast.LENGTH_SHORT).show();
	            } else {
	                Toast.makeText(getApplicationContext(), "Left Swipe", Toast.LENGTH_SHORT).show();
	            }
	            return true;
	        }
	        else if (Math.abs(dX) < SWIPE_MAX_OFF_PATH && Math.abs(velocityY)>=SWIPE_THRESHOLD_VELOCITY && Math.abs(dY)>=SWIPE_MIN_DISTANCE ) {
	            if (dY>0) {
	                Toast.makeText(getApplicationContext(), "Up Swipe", Toast.LENGTH_SHORT).show();
	            } else {
	                Toast.makeText(getApplicationContext(), "Down Swipe", Toast.LENGTH_SHORT).show();
	            }
	            return true;
	        }
	        return false;
	    }
	}
	
	protected class TouchListener implements View.OnTouchListener
	{
		GestureDetector mGestureDetector;
		
		public TouchListener(GestureDetector gestureDetector) {
			mGestureDetector = gestureDetector;
		}
		
	    @Override
	    public boolean onTouch(View v, MotionEvent e)
	    {
	        if (mGestureDetector.onTouchEvent(e)){
	            return true;
	        }else{
	            return false;
	        }
	    }
	}
}
